home *** CD-ROM | disk | FTP | other *** search
- /*
- * This file is part of the portable Forth environment written in ANSI C.
- * Copyright (C) 1995 Dirk Uwe Zoller
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * This file is version 0.9.13 of 17-July-95
- * Check for the latest version of this package via anonymous ftp at
- * roxi.rz.fht-mannheim.de:/pub/languages/forth/pfe-VERSION.tar.gz
- * or sunsite.unc.edu:/pub/languages/forth/pfe-VERSION.tar.gz
- * or ftp.cygnus.com:/pub/forth/pfe-VERSION.tar.gz
- *
- * Please direct any comments via internet to
- * duz@roxi.rz.fht-mannheim.de.
- * Thank You.
- */
- /*-
- * termunix.c --- Terminal driver for UNIX-like systems using
- * termcap or the termcap emulation in curses.
- *
- * Refer to this file as an example of how to write such a driver, though
- * other drivers for non-portable operating systems should be much simpler.
- * E.g. on an IBM-PC you could do everything here with a few INT-10h calls.
- *
- * (duz 24Feb94)
- */
-
- #include "forth.h"
- #include "support.h"
- #include "term.h"
-
- #include <stdio.h> /* putchar() */
- #include <stdlib.h> /* getenv() */
- #include <string.h> /* strlen() */
- #include <errno.h> /* EINTR */
-
- #include "nonansi.h"
- #include "missing.h"
-
- /*-
- * Table of contents
- *
- * 1 Initialization for usage of screen package
- * 1.1 File system, blocking/nonblocking io
- * 1.2 Setting tty driver flags
- * 1.2.1 Old System-V (termio) and Posix (termios) styles
- * 1.2.2 V7 and BSD style
- * 2 Getting information about the terminal
- * 2.1 Simply assume vt100
- * 2.2 Use termcap
- * 2.3 Use terminfo
- */
-
-
- /*-
- * 1 Initialization for usage of screen package
- *
- * All this stuff isn't neccessary or very easy on non unix-like machines
- * where there are direct console i/o functions available. See term-emx.c.
- * It implements the three required functions:
- *
- * - prepare_terminal() called once at startup
- * - interactive_terminal() called to set up the terminal for pfe
- * - system_terminal() called to reset the terminal on exit
- *
- * One problem is that in Unix-like OS console i/o is done via the
- * file system. It takes a little hacking to get an interactive
- * flavour from this arrangement. The kind of hacking changes while
- * Unix evolves. The hacking is addressed at two instances:
- *
- * - UNIX file system. fcntl() calls on the standard input are used
- * to prevent it from waiting for a pressed key when we only want
- * to detect if a key is pressed.
- *
- * - terminal device driver. It must be configured to pass keys
- * immediately instead of assembling it to lines, to pass through
- * all keys and not interpret some of them or interpret those keys
- * we need in a way we want.
- *
- * All what's changed must be carefully restored on exit otherwise
- * the terminal won't work any more.
- */
-
- /*
- * 1.1 file system, blocking/nonblocking io:
- */
-
- #ifndef O_NONBLOCK
- # ifdef O_NDELAY
- # define O_NONBLOCK O_NDELAY
- # else
- # error "neither O_NONBLOCK nor O_NDELAY defined"
- # endif
- #endif
-
- static int saved_fcntl[3];
-
- static void /* set file associated with fd to */
- waitchar (int fd) /* "wait for character" */
- {
- int flags;
-
- flags = fcntl (fd, F_GETFL, 0);
- fcntl (fd, F_SETFL, flags & ~O_NONBLOCK);
- }
-
- static void /* set file associated with fd to */
- no_waitchar (int fd) /* "don't wait for character" */
- {
- int flags;
-
- flags = fcntl (fd, F_GETFL, 0);
- fcntl (fd, F_SETFL, flags | O_NONBLOCK);
- }
-
- /*
- * 1.2 tty hacking, two major styles:
- */
-
- #if (defined HAVE_TERMIO_H || defined HAVE_TERMIOS_H) && !defined NeXTstep
-
- /*
- * 1.2.1 old System-V (termio) and Posix (termios) styles
- */
-
- #if defined HAVE_TERMIOS_H
-
- #include <termios.h>
-
- #elif defined HAVE_TERMIO_H
-
- #include <termio.h>
-
- /* make old SysV style look enough like Posix: */
- #define termios termio
- #define tcsetattr(F,X,M) ioctl (F, TCSETAW, M)
- #define tcgetattr(F,M) ioctl (F, TCGETA, M)
-
- #ifndef VINTR
- #define VINTR 0
- #endif
- #ifndef VQUIT
- #define VQUIT 1
- #endif
- #ifndef VMIN
- #define VMIN 4
- #endif
- #ifndef VTIME
- #define VTIME 5
- #endif
-
- #endif
-
- static struct termios tty_system;
- #define tty_save() tcgetattr (STDIN_FILENO, &tty_system)
- #define tty_restore() tcsetattr (STDIN_FILENO, TCSAFLUSH, &tty_system)
- #ifdef CBAUD
- # define tty_ospeed (tty_system.c_cflag & CBAUD)
- #else
- # define tty_ospeed (tty_system.c_ospeed)
- #endif
-
- int
- tty_interrupt_key (char ch)
- /*
- * If ch != 0 enables SIGINT on key ch, else disables SIGINT
- * returns old break key.
- * Porting this function might be hard. It isn't neccessary though.
- * This is needed only by the block editor: What's usually the break key
- * means exit to the block editor. If you have no break key or you have
- * it somewhere else than ^U, just #define this to nothing in term.h.
- */
- {
- struct termios tty;
- int old;
-
- if (!isatty (0))
- return -1;
- if (tcgetattr (STDIN_FILENO, &tty) != 0)
- return -1;
- old = tty.c_cc[VINTR];
- if (ch)
- {
- tty.c_iflag |= BRKINT;
- tty.c_cc[VINTR] = 0xFF;
- }
- else
- {
- tty.c_iflag &= ~BRKINT;
- tty.c_cc[VINTR] = ch;
- }
- tcsetattr (0, TCSAFLUSH, &tty);
- return old;
- }
-
- #define C_IFLAGS_OFF (ICRNL | IGNBRK | IGNCR | INLCR | \
- ISTRIP | IXOFF | IXON)
- #define C_IFLAGS_ON (BRKINT)
- #define C_OFLAGS_OFF (0)
- #define C_OFLAGS_ON (0)
- #define C_LFLAGS_OFF (ECHO | ICANON)
- #define C_LFLAGS_ON (ISIG)
-
- static void
- tty_interactive (void)
- {
- struct termios tty = tty_system;
-
- if (!isatty (STDIN_FILENO) || option.canonical)
- return;
- tty.c_iflag &= ~C_IFLAGS_OFF, tty.c_iflag |= C_IFLAGS_ON;
- tty.c_oflag &= ~C_OFLAGS_OFF, tty.c_oflag |= C_OFLAGS_ON;
- tty.c_lflag &= ~C_LFLAGS_OFF, tty.c_lflag |= C_LFLAGS_ON;
- tty.c_cc[VMIN] = 1;
- tty.c_cc[VTIME] = 0;
- tty.c_cc[VINTR] = INTR_KEY;
- tty.c_cc[VQUIT] = QUIT_KEY;
- #if defined HAVE_TERMIOS_H
- tty.c_cc[VSUSP] = SUSP_KEY;
- tty.c_cc[VSTART] = '\xFF';
- tty.c_cc[VSTOP] = '\xFF';
- #endif
- tcsetattr (STDIN_FILENO, TCSAFLUSH, &tty);
- }
-
- #elif defined HAVE_SGTTY_H
-
- /*
- * 1.2.2 V7 and BSD style, when struct sgttyb is defined
- */
-
- #include <sgtty.h>
-
- static struct
- {
- struct sgttyb sg;
- struct tchars tc;
- int lc; /* local mode word */
- }
- tty_system;
-
- #define tty_save() ioctl (STDIN_FILENO, TIOCGETP, &tty_system.sg), \
- ioctl (STDIN_FILENO, TIOCGETC, &tty_system.tc), \
- ioctl (STDIN_FILENO, TIOCLGET, &tty_system.lc)
- #define tty_restore() ioctl (STDIN_FILENO, TIOCSETP, &tty_system.sg), \
- ioctl (STDIN_FILENO, TIOCSETC, &tty_system.tc), \
- ioctl (STDIN_FILENO, TIOCLSET, &tty_system.lc)
- #define tty_ospeed (tty_system.sg.sg_ospeed)
-
- int
- tty_interrupt_key (char ch)
- /*
- * If ch != 0 enables SIGINT on key ch, else disables SIGINT
- * returns old break key.
- * Porting this function might be hard. It isn't neccessary though.
- * This is needed only by the block editor: What's usually the break key
- * means exit to the block editor. If you have no break key or you have
- * it somewhere else than ^U, just #define this to nothing in term.h.
- */
- {
- struct tchars tc;
- int old;
-
- if (!isatty (0))
- return -1;
- if (ioctl (STDIN_FILENO, TIOCGETC, &tc) != 0)
- return -1;
- old = tc.t_intrc;
- tc.t_intrc = ch == 0 ? -1 : ch;
- ioctl (STDIN_FILENO, TIOCSETC, &tc);
- return old == -1 ? 0 : old;
- }
-
- #define C_FLAGS_OFF (LCASE | ECHO | RAW)
- #define C_FLAGS_ON (CBREAK)
- #define L_FLAGS_ON (LTOSTOP | LPASS8OUT)
-
- static void
- tty_interactive (void)
- {
- struct sgttyb sg = tty_system.sg;
- struct tchars tc = tty_system.tc;
- int flags;
-
- if (!isatty (STDIN_FILENO) || option.canonical)
- return;
- sg.sg_flags &= ~C_FLAGS_OFF;
- sg.sg_flags |= C_FLAGS_ON;
- tc.t_intrc = INTR_KEY;
- tc.t_quitc = QUIT_KEY;
- tc.t_startc = -1;
- tc.t_stopc = -1;
- ioctl (STDIN_FILENO, TIOCSETP, &sg);
- ioctl (STDIN_FILENO, TIOCSETC, &tc);
- flags = L_FLAGS_ON;
- ioctl (STDIN_FILENO, TIOCLBIS, &flags);
- }
-
- #else
-
- #error "neither termios.h/termio.h nor sgtty.h available"
-
- #endif /* tty hacking, two major styles */
-
- /*-
- * 2 Getting information about the terminal
- *
- * The next problem is to get information about the connected terminal.
- * UNIX employs a database file called termcap or (in newer versions)
- * terminfo, where informations on the actually used terminal are
- * stored. Before we begin we must retrieve these information from the
- * data base. Three versions of the retrieval:
- *
- * - don't read databases but assume vt100
- * - use termcap or the termcap emulation in curses
- * - use terminfo
- */
-
- /* If nothing is decided yet, make a guess what should work.
- Note that you can override this with -DUSE_TERMCAP even if no
- termcap.h is avavailable in your system. Just in case the terminfo
- calls work worse than the termcap emulation inside curses. */
-
- #if !defined ASSUME_VT100 && !defined USE_TERMCAP && !defined USE_TERMINFO
- # if defined HAVE_TERMCAP_H
- # define USE_TERMCAP
- # elif defined HAVE_CURSES_H && defined HAVE_TERM_H
- # define USE_TERMINFO
- # else
- # define ASSUME_VT100
- # endif
- #endif
-
- #if defined ASSUME_VT100 || defined USE_TERMCAP
-
- /*
- * We make termcap look like terminfo. The following identifiers stand
- * for capabilities and are declared in term.h when using terminfo.
- * Otherwise they are used as indices to vectors containing capability
- * names or escape sequences. In the latter case they must be declared
- * in the same order as the initializers to the vectors of capability
- * names below.
- */
- enum
- {
- cursor_address,
- cursor_home,
- cursor_left,
- cursor_right,
- cursor_up,
- cursor_down,
- clear_screen,
- clr_eos,
- clr_eol,
- bell,
- delete_character,
- delete_line,
- scroll_forward,
- scroll_reverse,
- enter_standout_mode,
- exit_standout_mode,
- enter_underline_mode,
- exit_underline_mode,
- enter_bold_mode,
- enter_reverse_mode,
- enter_blink_mode,
- exit_attribute_mode,
- keypad_xmit,
- keypad_local
- };
-
- #endif
-
- /*
- * Strings used to query the termcap database.
- *
- * (In case terminfo is * used, these are only needed to satisfy the
- * show_*_strings * functions.)
- */
-
- static char tckeycode[][3] =
- {
- "k1", "k2", "k3", "k4", "k5", /* keys in same order as enum keycode */
- "k6", "k7", "k8", "k9", "k0", /* from term.h */
- "kl", "kr", "ku", "kd", /* result is just what has to be exported */
- "kh", "kH", "kN", "kP", /* via variable rawkey_string */
- "kb", "kD", "kM", "kI",
- "kA", "kE", "kL", "kC"
- };
-
- static char tcctlcode[][3] =
- {
- "cm", "ho",
- "le", "nd", "up", "do",
- "cl", "cd", "ce", "bl",
- "dc", "dl",
- "sf", "sr",
- "so", "se", "us", "ue",
- "md", "mr", "mb", "me",
- "ks", "ke"
- };
-
- #if defined ASSUME_VT100
-
- /*
- * 2.1 simply assume the terminal understands vt100 codes
- */
-
- static char *control_string[] = /* Some hardcoded vt100 sequences. */
- {
- "\033[%i%d;%dH", /* cm - cursor move */
- "\033[H", /* ho - home position */
-
- "\b", /* le - cursor left */
- "\033[C", /* nd - right one column */
- "\033[A", /* up - up one column */
- "\n", /* do - down one column */
-
- "\033[H\033[2J", /* cl - clear screen and home */
- "\033[J", /* cd - clear down */
- "\033[K", /* ce - clear to end of line */
- "\a", /* bl - bell */
-
- "\033[P", /* dc - delete character in line */
- "\033[M", /* dl - delete line from screen */
-
- "\033D", /* sf - scroll screen up */
- "\033M", /* sr - scroll screen down */
-
- "\033[7m", /* so - enter standout mode */
- "\033[m", /* se - leave standout mode */
- "\033[4m", /* us - turn on underline mode */
- "\033[m", /* ue - turn off underline mode */
-
- "\033[1m", /* md - enter double bright mode */
- "\033[7m", /* mr - enter reverse video mode */
- "\033[5m", /* mb - enter blinking mode */
- "\033[m", /* me - turn off all appearance modes */
-
- "\033[?1h\033=", /* ks - make function keys transmit */
- "\033[?1l\033>" /* ke - make function keys work locally */
- };
-
- char *rawkey_string[] = /* Strings sent by function keys */
- {
- "\033OP", /* k1 - function keys 1 - 4 from vt100 */
- "\033OQ", /* k2 */
- "\033OR", /* k3 */
- "\033OS", /* k4 */
- "\033[15~", /* k5 - function keys 5 - 10 from xterm */
- "\033[17~", /* k6 */
- "\033[18~", /* k7 */
- "\033[19~", /* k8 */
- "\033[20~", /* k9 */
- "\033[21~", /* k0 */
-
- "\033OD", /* kl - arrow left */
- "\033OC", /* kr - arrow right */
- "\033OA", /* ku - arrow up */
- "\033OB", /* kd - arrow down */
-
- "\033[1~", /* kh - home key */
- "\033[4~", /* kH - home down key (end key) */
- "\033[6~", /* kN - next page */
- "\033[5~", /* kP - previous page */
-
- "\b", /* kb - backspace key */
- "\033[3~", /* kD - delete character key */
- NULL, /* kM - exit insert mode key */
- "\033[2~", /* kI - insert character key */
-
- NULL, /* kA - insert line key */
- NULL, /* kE - clear end of line key */
- NULL, /* kL - delete line key */
- NULL, /* kC - clear screen key */
- };
-
- #define query_database() 1 /* nothing to query */
- #define t_putc(C) putchar (C)
-
- #define tputs(S,P,F) fputs (S, stdout)
-
- void
- t_puts (int cap, int n)
- {
- fputs (control_string[cap], stdout);
- }
-
- char *
- tparm (int cap, int x, int y) /* call this only with `cm' */
- {
- static char buf[12];
- sprintf (buf, "\033[%d;%dH", x + 1, y + 1);
- return buf;
- }
-
- #elif defined USE_TERMCAP
-
- /*
- * 2.2 Use termcap calls to retrieve information about the terminal
- */
-
- #ifdef HAVE_TERMCAP_H
- #include <termcap.h>
- #else
-
- /* Systems emulating the termcap functions in the curses library
- * usually haven't declared them in a file <termcap.h>, so here are
- * these declarations: */
- #ifdef __cplusplus
- extern "C"
- {
- #endif
- int tgetent (char *, char *);
- int tgetnum (char *);
- int tgetflag (char *);
- char *tgetstr (char *, char **);
- int tputs (char *, int, int (*)(int));
- char *tgoto (char *, int, int);
- #ifdef __cplusplus
- }
- #endif
-
- #endif
-
- static char *control_string[DIM (tcctlcode)];
- char *rawkey_string[NO_OF_KEYS];
-
- static int
- query_database (void)
- /*
- * Get the strings needed out of termcap/terminfo.
- * Store them for later use in control_string[] and rawkey_string[].
- */
- {
- char *ttype = getenv ("TERM");
- char tcent[2048];
- static char tcbuf[2048];
- char *tctop = tcbuf;
- int i;
-
- if (ttype == NULL || tgetent (tcent, ttype) <= 0)
- return 0;
-
- #if HAVE_TERMCAP_H
- {
- char *pc = tgetstr ("pc", &tctop);
- if (pc != NULL)
- PC = *pc;
- else
- PC = 0;
- }
- #endif
-
- rows = tgetnum ("li");
- cols = tgetnum ("co");
-
- /* Read all termcap strings we need, */
- for (i = 0; i < NO_OF_KEYS; i++)
- rawkey_string[i] = tgetstr (tckeycode[i], &tctop);
- /* rawkey_string [EKEY_enter - EKEY_k1] = "\r"; */
- for (i = 0; i < DIM (tcctlcode); i++)
- control_string[i] = tgetstr (tcctlcode[i], &tctop);
- if (control_string [cursor_left] == NULL)
- control_string [cursor_left] = "\b";
-
- #if defined HAVE_OSPEED
- {
- char *pc = tgetstr ("pc", &tctop);
- /* these are defined inside the termcap-library: */
- ospeed = tty_ospeed;
- PC = pc ? *pc : 0;
- BC = control_string[cursor_left];
- UP = control_string[cursor_up];
- }
- #endif
- return 1;
- }
-
- static int /* utility function for tputs(): */
- t_putc (int c) /* putchar() is a macro, we need a function */
- {
- return putchar (c);
- }
-
- static void
- t_puts (int tcidx, int n) /* issue termcap string to terminal */
- {
- if (!control_string[tcidx])
- /* no harm if feature not available */
- return;
- tputs (control_string[tcidx], n, t_putc);
- fflush (stdout);
- }
-
- #define tparm(CAP,X,Y) tgoto (control_string [CAP], Y, X)
-
- #elif defined USE_TERMINFO
-
- /*
- * 2.3 Use terminfo calls to retrieve information about the terminal
- */
-
- #include <curses.h>
- #include <term.h>
-
- static char *control_string[DIM (tcctlcode)];
- char *rawkey_string[NO_OF_KEYS];
-
- static int
- query_database (void)
- {
- int errret;
-
- setupterm (NULL, STDOUT_FILENO, &errret);
- if (errret != 1)
- return 0;
-
- #define KINIT(key, ti_capability) \
- rawkey_string [APPEND (EKEY_,key) - EKEY_k1] = ti_capability
-
- KINIT (k1, key_f1); /* function keys F1 through F10 */
- KINIT (k2, key_f2);
- KINIT (k3, key_f3);
- KINIT (k4, key_f4);
- KINIT (k5, key_f5);
- KINIT (k6, key_f6);
- KINIT (k7, key_f7);
- KINIT (k8, key_f8);
- KINIT (k9, key_f9);
- KINIT (k0, key_f10);
-
- KINIT (kl, key_left); /* arrow key left */
- KINIT (kr, key_right); /* arrow key right */
- KINIT (ku, key_up); /* arrow key up */
- KINIT (kd, key_down); /* arrow key down */
-
- KINIT (kh, key_home); /* home key */
- KINIT (kH, key_end); /* home down key */
- KINIT (kN, key_npage); /* next page key */
- KINIT (kP, key_ppage); /* previous page key */
-
- KINIT (kb, key_backspace); /* backspace key */
- KINIT (kD, key_dc); /* delete character key */
- KINIT (kM, key_eic); /* exit insert mode key */
- KINIT (kI, key_ic); /* insert character key */
-
- KINIT (kA, key_il); /* insert line key */
- KINIT (kE, key_eol); /* clear to end of line key */
- KINIT (kL, key_dl); /* delete line key */
- KINIT (kC, key_clear); /* clear screen key */
-
- #undef KINIT
- if (cursor_left == NULL)
- cursor_left = "\b";
- return 1;
- }
-
- static int /* utility function for tputs(): */
- t_putc (char c) /* putchar() is a macro, we need a function */
- {
- return putchar (c);
- }
-
- static void /* output capability with affected lines cnt */
- t_puts (char *s, int n)
- {
- tputs (s, n, t_putc);
- fflush (stdout);
- }
-
- #else
-
- #error "One of ASSUME_VT100, USE_TERMCAP or USE_TERMINFO must be set."
-
- #endif
-
- void
- show_control_strings (int (*outf) (const char *fmt,...))
- /* for your information why screen manipulation doesn't work :-) */
- {
- int i;
- char *p;
-
- for (i = 0; i < DIM (tcctlcode); i++)
- {
- outf ("\n\"%s\"=", tcctlcode[i]);
- if ((p = control_string[i]))
- while (*p)
- c_putc_printable (*p++);
- else
- c_puts ("undefined");
- }
- }
-
- void
- show_rawkey_strings (int (*outf) (const char *fmt,...))
- /* for your information why function keys don't work :-) */
- {
- int i;
- char *p;
-
- for (i = 0; i < DIM (tckeycode); i++)
- {
- outf ("\n\"%s\"=", tckeycode[i]);
- if ((p = rawkey_string[i]))
- while (*p)
- c_putc_printable (*p++);
- else
- c_puts ("undefined");
- }
- }
-
- int /* Prepares usage of all other functions. */
- prepare_terminal (void) /* Call only once at startup. */
- {
- int fd;
-
- /* save state before all changes */
- for (fd = 0; fd < 3; fd++)
- saved_fcntl[fd] = fcntl (fd, F_GETFL, 0);
- tty_save ();
-
- /* initialize termcap-stuff */
- return query_database ();
- }
-
- void /* set terminal to the sort of */
- interactive_terminal (void) /* `cbreak' mode used by pfe */
- {
- tty_interactive ();
- t_puts (keypad_xmit, 0);
- }
-
- void /* resets terminal state to */
- system_terminal (void) /* as it was before */
- {
- int fd;
-
- if (!isatty (STDIN_FILENO) || option.canonical)
- return;
- fflush (stdout);
- tty_restore ();
- t_puts (keypad_local, 0);
- for (fd = 0; fd < 3; fd++)
- fcntl (fd, F_SETFL, saved_fcntl[fd]);
- }
-
- /*
- * Handle window size change, see also signal.c:
- */
- #ifdef TIOCGWINSZ
- void
- query_winsize (void)
- {
- struct winsize size;
-
- if (ioctl (1, TIOCGWINSZ, (char *) &size) >= 0)
- {
- rows = size.ws_row;
- cols = size.ws_col;
- xmax = size.ws_xpixel;
- ymax = size.ws_ypixel;
- }
- }
- #else
- void
- query_winsize (void)
- {
- }
- #endif
-
- /************************************************************************/
- /* Input from keyboard. */
- /************************************************************************/
-
- /*
- * Having hacked the terminal driver and the standard input in the
- * appropiate modes all we have to do is read one character from
- * standard input to get a key.
- * The only problem is: we can't detect if a key is available without
- * reading it. So we have to store it in this case.
- */
-
- #define NOCH ((unsigned short)0xABCD)
- /* encodes 'no character available' */
-
- static unsigned short /* the next character when read by */
- nxch = NOCH; /* keypressed() */
-
- static int
- nextch (void)
- /*
- * Read a single character from standard input.
- */
- {
- unsigned char c;
-
- if (nxch != NOCH)
- {
- c = (unsigned char) nxch;
- nxch = NOCH;
- return c;
- }
- else
- for (;;)
- switch (read (0, &c, 1))
- {
- case -1:
- switch (errno)
- {
- default:
- return -1;
- case EAGAIN:
- case EINTR:
- continue;
- }
- case 0:
- return -1;
- default:
- return c;
- }
- }
-
- int
- c_keypressed (void)
- /*
- * Checks if a character is available in the standard input. Saves it in nxch.
- * Returns: 1 if char available, 0 otherwise
- */
- {
- unsigned char c; /* place to read the character */
- int result;
-
- fflush (stdout);
- if (nxch != NOCH)
- return 1; /* char from previos keypressed() */
- no_waitchar (STDIN_FILENO);
- result = read (0, &c, 1);
- waitchar (STDIN_FILENO);
- if (result != 1)
- return 0;
- nxch = c;
- return 1;
- }
-
- int
- c_getkey (void)
- {
- fflush (stdout);
- return nextch ();
- }
-
- /************************************************************************/
- /* Output to screen, control with termcap: */
- /************************************************************************/
-
- static int row, col; /* position of curser as tracked */
-
- void /* output character and */
- c_putc_noflush (char c) /* trace the cursor position */
- {
- putchar (c);
- switch (c)
- {
- case '\a': /* bell, no change of cursor position */
- break;
- case '\b': /* backspace, move cursor left */
- if (col > 0)
- col--;
- break;
- case '\r': /* carriage return, ->column 0 */
- col = 0;
- break;
- default: /* ordinary character: */
- if (col < cols - 1) /* at right edge of screen? */
- {
- col++; /* no: increment column */
- break;
- } /* yes: like line feed */
- case '\n': /* line feed */
- col = 0;
- if (row < rows - 1) /* if not at bottom of screen: */
- row++; /* increment row */
- } /* otherwise terminal is supposed to scroll */
- }
-
- void
- c_flush (void)
- {
- fflush (stdout);
- }
-
- void
- c_putc (char c)
- {
- c_putc_noflush (c);
- fflush (stdout);
- }
-
- void
- c_puts (const char *s)
- {
- while (*s)
- c_putc_noflush (*s++);
- fflush (stdout);
- }
-
- void
- c_gotoxy (int x, int y)
- {
- tputs (tparm (cursor_address, y, x), 1, t_putc);
- fflush (stdout);
- col = x;
- row = y;
- }
-
- void
- c_wherexy (int *x, int *y)
- {
- *x = col;
- *y = row;
- }
-
- /* *INDENT-OFF* */
- void c_goleft (void) { t_puts (cursor_left, 0); --col; }
- void c_goright (void) { t_puts (cursor_right, 0); ++col; }
- void c_goup (void) { t_puts (cursor_up, 0); --row; }
- void c_godown (void) { t_puts (cursor_down, 0); ++row; }
-
- void c_home (void) { t_puts (cursor_home, 1); row = col = 0; }
- void c_clrscr (void) { t_puts (clear_screen, rows); c_home (); }
- void c_clreol (void) { t_puts (clr_eol, 1); }
- void c_clrdown (void) { t_puts (clr_eos, rows - row); }
- void c_bell (void) { t_puts (bell, 0); }
-
- void c_standout_on (void) { t_puts (enter_standout_mode, 0); }
- void c_standout_off (void) { t_puts (exit_standout_mode, 0); }
- void c_underline_on (void) { t_puts (enter_underline_mode, 0); }
- void c_underline_off (void) { t_puts (exit_underline_mode, 0); }
- void c_bright (void) { t_puts (enter_bold_mode, 0); }
- void c_reverse (void) { t_puts (enter_reverse_mode, 0); }
- void c_blinking (void) { t_puts (enter_blink_mode, 0); }
- void c_normal (void) { t_puts (exit_attribute_mode, 0); }
-